import sys
from vcd import parse_vcd

path_code_map = {}

vcd = parse_vcd('/tmp/vcd')
for code, v in vcd.items():
    for net in v['nets']:
        path = net['hier'] + '.' + net['name']
        path_code_map[path] = code

def get_tv(path):
    code = path_code_map[path]
    return vcd[code]['tv']

def value_at(tv, time):
    if time < tv[0][0]:
        raise ValueError
    if time >= tv[-1][0]:
        return tv[-1][1]
    len1 = len(tv) >> 1
    tv1 = tv[:len1]
    tv2 = tv[len1:]
    if time < tv2[0][0]:
        return value_at(tv1, time)
    else:
        return value_at(tv2, time)

def get_value(path, time):
    tv = get_tv(path)
    return value_at(tv, time)

tv_stall = get_tv('tb.u_top.u_core.stall') # list of tuples

tv_decode_valid = get_tv('tb.u_top.u_core.u_decode.valid')
tv_decode_instr = get_tv('tb.u_top.u_core.u_decode.i[31:0]')

tv_gpr_we   = get_tv('tb.u_top.u_core.u_regbank.i_rd_we')
tv_gpr_wsel = get_tv('tb.u_top.u_core.u_regbank.i_rd_w[4:0]')
tv_gpr_wd   = get_tv('tb.u_top.u_core.u_regbank.i_rd_wd[31:0]')

tv_pc       = get_tv('tb.u_top.u_core.u_regbank.o_pc[31:0]')

tv_mem_we   = get_tv('tb.u_top.u_core.u_execute.o_store')
tv_mem_addr = get_tv('tb.u_top.u_core.u_execute.o_ls_addr[31:0]')
tv_mem_wd   = get_tv('tb.u_top.u_core.u_execute.o_mem_wd[31:0]')
tv_mem_sel  = get_tv('tb.u_top.u_core.u_execute.o_ls_sel[3:0]')

tv_branch      = get_tv('tb.u_top.u_core.u_execute.o_branch')
tv_branch_dest = get_tv('tb.u_top.u_core.u_execute.o_branch_dest[31:0]')

tv_cpsr_we = get_tv('tb.u_top.u_core.u_cpsr.i_we')
tv_cpsr_wd = get_tv('tb.u_top.u_core.u_cpsr.i_wd[31:0]')

tv_spsr_we   = get_tv('tb.u_top.u_core.u_spsr.i_we')
tv_spsr_wsel = get_tv('tb.u_top.u_core.u_spsr.i_wbank[2:0]')
tv_spsr_wd   = get_tv('tb.u_top.u_core.u_spsr.i_wd[31:0]')

T = 20000
end = 3000000

gpr_name = [
        'R0',
        'R1',
        'R2',
        'R3',
        'R4',
        'R5',
        'R6',
        'R7',
        'R8',
        'R9',
        'R10',
        'R11',
        'R12',
        'R13',
        'R14',
        'PC',
        'R13_svc',
        'R14_svc',
        'R13_abt',
        'R14_abt',
	'R13_und',
	'R14_und',
	'R13_irq',
	'R14_irq',
	'R8_fiq',
	'R9_fiq',
	'R10_fiq',
	'R11_fiq',
	'R12_fiq',
	'R13_fiq',
	'R14_fiq'
]

spsr_name = [
        'SPSR_svc',
        'SPSR_abt',
        'SPSR_und',
        'SPSR_irq',
        'SPSR_fiq',
        'SPSR_???'
]

keypoints = []

for t in range(T, end, T):
    if value_at(tv_stall, t) == '0':
        keypoints.append(t)

for i, t in enumerate(keypoints):
    if value_at(tv_decode_valid, t) == '1':
        if i+1 < len(keypoints):
            nextkp = keypoints[i+1]
            instr = int(value_at(tv_decode_instr, t), 2)
            pc = int(value_at(tv_pc, t), 2)
            print('@%08x %08x' % (pc-4, instr))
            next_span = range(t+T, nextkp+T, T)
            for t2 in next_span:
                # GPR write
                if value_at(tv_gpr_we, t2) == '1':
                    wsel = int(value_at(tv_gpr_wsel, t2), 2)
                    wd   = int(value_at(tv_gpr_wd,   t2), 2)
                    print('%s = %08x' % (gpr_name[wsel], wd))
                # memory write
                if value_at(tv_mem_we, t2) == '1':
                    addr = int(value_at(tv_mem_addr, t2), 2)
                    wd   = int(value_at(tv_mem_wd,   t2), 2)
                    sel  = int(value_at(tv_mem_sel,  t2), 2)
                    for bit in range(4):
                        if sel&(1<<bit):
                            print('[%08x] = %02x' % (addr&0xfffffffc|bit, (wd >> 8*bit) & 0xff))
                # CPSR
                if value_at(tv_cpsr_we, t2) == '1':
                    wd = int(value_at(tv_cpsr_wd, t2), 2)
                    print('CPSR = %08x' % wd)
                # SPSR
                if value_at(tv_spsr_we, t2) == '1':
                    wsel = int(value_at(tv_spsr_wsel, t2), 2)
                    wd   = int(value_at(tv_spsr_wd,   t2), 2)
                    print('%s = %08x' % (spsr_name[wsel], wd))
            # branch
            if value_at(tv_branch, nextkp) == '1':
                print('GOTO %08x' % int(value_at(tv_branch_dest, nextkp), 2))
